/*
 * Copyright 2004-2014 SmartBear Software
 *
 * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
 * versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://ec.europa.eu/idabc/eupl
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
 * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the Licence for the specific language governing permissions and limitations
 * under the Licence.
*/

package com.eviware.soapui.impl.wsdl.teststeps;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.config.RequestStepConfig;
import com.eviware.soapui.config.TestStepConfig;
import com.eviware.soapui.impl.support.http.HttpRequestTestStep;
import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.WsdlRequest;
import com.eviware.soapui.impl.wsdl.WsdlSubmit;
import com.eviware.soapui.impl.wsdl.submit.transports.http.BaseHttpRequestTransport;
import com.eviware.soapui.impl.wsdl.submit.transports.http.WsdlResponse;
import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.WsdlSinglePartHttpResponse;
import com.eviware.soapui.impl.wsdl.support.assertions.AssertedXPathsContainer;
import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
import com.eviware.soapui.impl.wsdl.teststeps.assertions.TestAssertionRegistry.AssertableType;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.iface.Interface;
import com.eviware.soapui.model.iface.Operation;
import com.eviware.soapui.model.iface.Request.SubmitException;
import com.eviware.soapui.model.iface.Submit;
import com.eviware.soapui.model.project.Project;
import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContainer;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansionsResult;
import com.eviware.soapui.model.support.DefaultTestStepProperty;
import com.eviware.soapui.model.support.InterfaceListenerAdapter;
import com.eviware.soapui.model.support.ModelSupport;
import com.eviware.soapui.model.support.ProjectListenerAdapter;
import com.eviware.soapui.model.support.TestStepBeanProperty;
import com.eviware.soapui.model.testsuite.Assertable;
import com.eviware.soapui.model.testsuite.AssertionError;
import com.eviware.soapui.model.testsuite.AssertionsListener;
import com.eviware.soapui.model.testsuite.OperationTestStep;
import com.eviware.soapui.model.testsuite.TestAssertion;
import com.eviware.soapui.model.testsuite.TestCaseRunContext;
import com.eviware.soapui.model.testsuite.TestCaseRunner;
import com.eviware.soapui.model.testsuite.TestStep;
import com.eviware.soapui.model.testsuite.TestStepResult;
import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
import com.eviware.soapui.security.Securable;
import com.eviware.soapui.support.resolver.ChangeOperationResolver;
import com.eviware.soapui.support.resolver.ImportInterfaceResolver;
import com.eviware.soapui.support.resolver.RemoveTestStepResolver;
import com.eviware.soapui.support.resolver.ResolveContext;
import com.eviware.soapui.support.resolver.ResolveContext.PathToResolve;
import com.eviware.soapui.support.types.StringToStringsMap;
import org.apache.log4j.Logger;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.XmlString;

import javax.swing.ImageIcon;
import javax.xml.namespace.QName;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * WsdlTestStep that executes a WsdlTestRequest
 *
 * @author Ole.Matzura
 */

public class WsdlTestRequestStep extends WsdlTestStepWithProperties implements OperationTestStep,
        PropertyChangeListener, PropertyExpansionContainer, Assertable, HttpRequestTestStep, Securable {
    private final static Logger log = Logger.getLogger(WsdlTestRequestStep.class);
    private RequestStepConfig requestStepConfig;
    private WsdlTestRequest testRequest;
    private WsdlOperation wsdlOperation;
    private final InternalProjectListener projectListener = new InternalProjectListener();
    private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
    private WsdlSubmit<WsdlRequest> submit;

    public WsdlTestRequestStep(WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest) {
        super(testCase, config, true, forLoadTest);

        if (getConfig().getConfig() != null) {
            requestStepConfig = (RequestStepConfig) getConfig().getConfig().changeType(RequestStepConfig.type);

            wsdlOperation = findWsdlOperation();
            if (wsdlOperation == null) {
                log.error("Could not find operation [" + requestStepConfig.getOperation() + "] in interface ["
                        + requestStepConfig.getInterface() + "] for test request [" + getName() + "] in TestCase ["
                        + getTestCase().getTestSuite().getName() + "/" + getTestCase().getName() + "]");
                // requestStepConfig.setRequest(null);
                setDisabled(true);
            } else {
                initTestRequest(config, forLoadTest);
            }
        } else {
            requestStepConfig = (RequestStepConfig) getConfig().addNewConfig().changeType(RequestStepConfig.type);
        }

        // init properties
        if (testRequest != null) {
            initRequestProperties();
        }
    }

    private void initRequestProperties() {
        addProperty(new TestStepBeanProperty("Endpoint", false, testRequest, "endpoint", this, false));
        addProperty(new TestStepBeanProperty("Username", false, testRequest, "username", this, true));
        addProperty(new TestStepBeanProperty("Password", false, testRequest, "password", this, true));
        addProperty(new TestStepBeanProperty("Domain", false, testRequest, "domain", this, false));
        addProperty(new TestStepBeanProperty("AuthType", false, testRequest, "authType", this, true) {

            @Override
            public String getDefaultValue() {
                // TODO Auto-generated method stub
                return "XXX";
            }
        });

        addProperty(new TestStepBeanProperty("Request", false, testRequest, "requestContent", this, true) {
            @Override
            public String getDefaultValue() {
                return getOperation().createRequest(true);
            }

            @Override
            public SchemaType getSchemaType() {
                try {
                    WsdlInterface iface = getOperation().getInterface();
                    if (WsdlUtils.isRpc(iface.getBinding())) {
                        return WsdlUtils.generateRpcBodyType(getOperation());
                    } else {
                        return iface.getDefinitionContext().getSchemaTypeSystem()
                                .findElement(getOperation().getRequestBodyElementQName()).getType();
                    }
                } catch (Exception e) {
                    SoapUI.logError(e);
                    return XmlString.type;
                }
            }

            @Override
            public QName getType() {
                return getSchemaType().getName();
            }

        });
        addProperty(new TestStepBeanProperty("Response", true, testRequest, "responseContent", this) {
            @Override
            public String getDefaultValue() {
                return getOperation().createResponse(true);
            }
        });

        addProperty(new DefaultTestStepProperty("RawRequest", true, this) {
            @Override
            public String getValue() {
                WsdlResponse response = testRequest.getResponse();
                return response == null ? null : response.getRequestContent();
            }
        });
    }

    private void initTestRequest(TestStepConfig config, boolean forLoadTest) {
        if (!forLoadTest) {
            wsdlOperation.getInterface().getProject().addProjectListener(projectListener);
            wsdlOperation.getInterface().addInterfaceListener(interfaceListener);

            // we need to listen for name changes which happen when
            // interfaces are updated..
            wsdlOperation.getInterface().addPropertyChangeListener(this);
            wsdlOperation.addPropertyChangeListener(this);
        }

        testRequest = new WsdlTestRequest(wsdlOperation, requestStepConfig.getRequest(), this, forLoadTest);
        testRequest.addPropertyChangeListener(this);

        if (config.isSetName()) {
            testRequest.setName(config.getName());
        } else {
            config.setName(testRequest.getName());
        }
    }

    @Override
    public WsdlTestStep clone(WsdlTestCase targetTestCase, String name) {
        beforeSave();

        TestStepConfig config = (TestStepConfig) getConfig().copy();
        RequestStepConfig stepConfig = (RequestStepConfig) config.getConfig().changeType(RequestStepConfig.type);

        while (stepConfig.getRequest().sizeOfAttachmentArray() > 0) {
            stepConfig.getRequest().removeAttachment(0);
        }

        config.setName(name);
        stepConfig.getRequest().setName(name);

        WsdlTestRequestStep result = (WsdlTestRequestStep) targetTestCase.addTestStep(config);
        testRequest.copyAttachmentsTo(result.getTestRequest());

        return result;
    }

    private WsdlOperation findWsdlOperation() {
        WsdlTestCase testCase = getTestCase();
        if (testCase == null || testCase.getTestSuite() == null) {
            return null;
        }

        Project project = testCase.getTestSuite().getProject();
        WsdlOperation operation = null;
        for (int c = 0; c < project.getInterfaceCount(); c++) {
            if (project.getInterfaceAt(c).getName().equals(requestStepConfig.getInterface())) {
                WsdlInterface iface = (WsdlInterface) project.getInterfaceAt(c);
                for (int i = 0; i < iface.getOperationCount(); i++) {
                    if (iface.getOperationAt(i).getName().equals(requestStepConfig.getOperation())) {
                        operation = iface.getOperationAt(i);
                        break;
                    }
                }

                if (operation != null) {
                    break;
                }
            }
        }
        return operation;
    }

    public String getInterfaceName() {
        return requestStepConfig.getInterface();
    }

    public String getOperationName() {
        return requestStepConfig.getOperation();
    }

    @Override
    public void release() {
        super.release();

        if (wsdlOperation == null) {
            wsdlOperation = findWsdlOperation();
        }

        if (wsdlOperation != null) {
            wsdlOperation.removePropertyChangeListener(this);
            wsdlOperation.getInterface().getProject().removeProjectListener(projectListener);
            wsdlOperation.getInterface().removeInterfaceListener(interfaceListener);
            wsdlOperation.getInterface().removePropertyChangeListener(this);
        }

        // could be null if initialization failed..
        if (testRequest != null) {
            testRequest.removePropertyChangeListener(this);
            testRequest.release();
        }
    }

    @Override
    public void resetConfigOnMove(TestStepConfig config) {
        super.resetConfigOnMove(config);

        requestStepConfig = (RequestStepConfig) config.getConfig().changeType(RequestStepConfig.type);
        testRequest.updateConfig(requestStepConfig.getRequest());
    }

    @Override
    public ImageIcon getIcon() {
        return testRequest == null ? null : testRequest.getIcon();
    }

    public WsdlTestRequest getTestRequest() {
        return testRequest;
    }

    @Override
    public void setName(String name) {
        super.setName(name);
        testRequest.setName(name);
    }

    public void propertyChange(PropertyChangeEvent event) {
        // TODO Some of these properties should be pulled up as they are common for may steps
        // FIXME The property names shouldn't be hardcoded
        if (event.getSource() == testRequest) {
            if (event.getNewValue() instanceof WsdlSinglePartHttpResponse) {
                WsdlSinglePartHttpResponse response = (WsdlSinglePartHttpResponse) event.getNewValue();
                WsdlRequest request = response.getRequest();
                byte[] rawRequest = response.getRawRequestData();

                firePropertyValueChanged("Response", String.valueOf(response), null);
                firePropertyValueChanged("Request", String.valueOf(request), null);
                firePropertyValueChanged("RawRequest", String.valueOf(rawRequest), null);
            }

            if (event.getPropertyName().equals("domain")) {
                delegatePropertyChange("Domain", event);
            } else if (event.getPropertyName().equals("password")) {
                delegatePropertyChange("Password", event);
            } else if (event.getPropertyName().equals("username")) {
                delegatePropertyChange("Username", event);
            } else if (event.getPropertyName().equals("endpoint")) {
                delegatePropertyChange("Endpoint", event);
            }
        }

        if (event.getSource() == wsdlOperation) {
            if (event.getPropertyName().equals(Operation.NAME_PROPERTY)) {
                requestStepConfig.setOperation((String) event.getNewValue());
            }
        } else if (event.getSource() == wsdlOperation.getInterface()) {
            if (event.getPropertyName().equals(Interface.NAME_PROPERTY)) {
                requestStepConfig.setInterface((String) event.getNewValue());
            }
        } else if (event.getPropertyName().equals(TestAssertion.CONFIGURATION_PROPERTY)
                || event.getPropertyName().equals(TestAssertion.DISABLED_PROPERTY)) {
            if (getTestRequest().getResponse() != null) {
                getTestRequest().assertResponse(new WsdlTestRunContext(this));
            }
        } else {
            if (event.getSource() == testRequest && event.getPropertyName().equals(WsdlTestRequest.NAME_PROPERTY)) {
                if (!super.getName().equals((String) event.getNewValue())) {
                    super.setName((String) event.getNewValue());
                }
            }

            notifyPropertyChanged(event.getPropertyName(), event.getOldValue(), event.getNewValue());
        }
    }

    private void delegatePropertyChange(String customPropertyname, PropertyChangeEvent event) {
        firePropertyValueChanged(customPropertyname, String.valueOf(event.getOldValue()),
                String.valueOf(event.getNewValue()));

    }

    public TestStepResult run(TestCaseRunner runner, TestCaseRunContext runContext) {
        WsdlTestRequestStepResult testStepResult = new WsdlTestRequestStepResult(this);
        testStepResult.startTimer();
        runContext.setProperty(AssertedXPathsContainer.ASSERTEDXPATHSCONTAINER_PROPERTY, testStepResult);

        try {
            submit = testRequest.submit(runContext, false);
            WsdlResponse response = (WsdlResponse) submit.getResponse();

            if (submit.getStatus() != Submit.Status.CANCELED) {
                if (submit.getStatus() == Submit.Status.ERROR) {
                    testStepResult.setStatus(TestStepStatus.FAILED);
                    testStepResult.addMessage(submit.getError().toString());

                    testRequest.setResponse(null, runContext);
                } else if (response == null) {
                    testStepResult.setStatus(TestStepStatus.FAILED);
                    testStepResult.addMessage("Request is missing response");

                    testRequest.setResponse(null, runContext);
                } else {
                    runContext.setProperty(AssertedXPathsContainer.ASSERTEDXPATHSCONTAINER_PROPERTY, testStepResult);
                    testRequest.setResponse(response, runContext);

                    testStepResult.setTimeTaken(response.getTimeTaken());
                    testStepResult.setSize(response.getContentLength());

                    switch (testRequest.getAssertionStatus()) {
                        case FAILED:
                            testStepResult.setStatus(TestStepStatus.FAILED);
                            break;
                        case VALID:
                            testStepResult.setStatus(TestStepStatus.OK);
                            break;
                        case UNKNOWN:
                            testStepResult.setStatus(TestStepStatus.UNKNOWN);
                            break;
                    }

                    testStepResult.setResponse(response, testStepResult.getStatus() != TestStepStatus.FAILED);
                }
            } else {
                testStepResult.setStatus(TestStepStatus.CANCELED);
                testStepResult.addMessage("Request was canceled");
            }

            if (response != null) {
                testStepResult.setRequestContent(response.getRequestContent(),
                        testStepResult.getStatus() != TestStepStatus.FAILED);
            } else {
                testStepResult.setRequestContent(testRequest.getRequestContent(),
                        testStepResult.getStatus() != TestStepStatus.FAILED);
            }
            testStepResult.stopTimer();
        } catch (SubmitException e) {
            testStepResult.setStatus(TestStepStatus.FAILED);
            testStepResult.addMessage("SubmitException: " + e);
            testStepResult.stopTimer();
        } finally {
            submit = null;
        }

        testStepResult.setDomain(PropertyExpander.expandProperties(runContext, testRequest.getDomain()));
        testStepResult.setUsername(PropertyExpander.expandProperties(runContext, testRequest.getUsername()));
        testStepResult.setPassword(PropertyExpander.expandProperties(runContext, testRequest.getPassword()));
        testStepResult.setEndpoint(PropertyExpander.expandProperties(runContext, testRequest.getEndpoint()));
        testStepResult.setEncoding(PropertyExpander.expandProperties(runContext, testRequest.getEncoding()));

        if (testStepResult.getStatus() != TestStepStatus.CANCELED) {
            AssertionStatus assertionStatus = testRequest.getAssertionStatus();
            switch (assertionStatus) {
                case FAILED: {
                    testStepResult.setStatus(TestStepStatus.FAILED);
                    if (getAssertionCount() == 0) {
                        testStepResult.addMessage("Invalid/empty response");
                    } else {
                        for (int c = 0; c < getAssertionCount(); c++) {
                            WsdlMessageAssertion assertion = getAssertionAt(c);
                            AssertionError[] errors = assertion.getErrors();
                            if (errors != null) {
                                for (AssertionError error : errors) {
                                    testStepResult.addMessage("[" + assertion.getName() + "] " + error.getMessage());
                                }
                            }
                        }
                    }

                    break;
                }
                // default : testStepResult.setStatus( TestStepStatus.OK ); break;
            }
        }

        if (testRequest.isDiscardResponse() && !SoapUI.getDesktop().hasDesktopPanel(this)) {
            testRequest.setResponse(null, runContext);
            runContext.removeProperty(BaseHttpRequestTransport.RESPONSE);
        }

        return testStepResult;
    }

    public WsdlMessageAssertion getAssertionAt(int index) {
        return testRequest.getAssertionAt(index);
    }

    public int getAssertionCount() {
        return testRequest == null ? 0 : testRequest.getAssertionCount();
    }

    public WsdlTestRequest getHttpRequest() {
        return testRequest;
    }

    public class InternalProjectListener extends ProjectListenerAdapter {
        @Override
        public void interfaceRemoved(Interface iface) {
            if (wsdlOperation != null && wsdlOperation.getInterface().equals(iface)) {
                log.debug("Removing test step due to removed interface");
                (getTestCase()).removeTestStep(WsdlTestRequestStep.this);
            }
        }
    }

    public class InternalInterfaceListener extends InterfaceListenerAdapter {
        @Override
        public void operationRemoved(Operation operation) {
            if (operation == wsdlOperation) {
                log.debug("Removing test step due to removed operation");
                (getTestCase()).removeTestStep(WsdlTestRequestStep.this);
            }
        }

        @Override
        public void operationUpdated(Operation operation) {
            if (operation == wsdlOperation) {
                requestStepConfig.setOperation(operation.getName());
            }
        }
    }

    @Override
    public boolean cancel() {
        if (submit == null) {
            return false;
        }

        submit.cancel();

        return true;
    }

    @Override
    public Collection<Interface> getRequiredInterfaces() {
        ArrayList<Interface> result = new ArrayList<Interface>();
        result.add(findWsdlOperation().getInterface());
        return result;
    }

    public String getDefaultSourcePropertyName() {
        return "Response";
    }

    public String getDefaultTargetPropertyName() {
        return "Request";
    }

    @Override
    public boolean dependsOn(AbstractWsdlModelItem<?> modelItem) {
        if (modelItem instanceof Interface && testRequest.getOperation().getInterface() == modelItem) {
            return true;
        } else if (modelItem instanceof Operation && testRequest.getOperation() == modelItem) {
            return true;
        }

        return false;
    }

    @Override
    public void beforeSave() {
        super.beforeSave();

        if (testRequest != null) {
            testRequest.beforeSave();
        }
    }

    @Override
    public String getDescription() {
        return testRequest == null ? "<missing>" : testRequest.getDescription();
    }

    @Override
    public void setDescription(String description) {
        if (testRequest != null) {
            testRequest.setDescription(description);
        }
    }

    public void setOperation(WsdlOperation operation) {
        if (wsdlOperation == operation) {
            return;
        }

        WsdlOperation oldOperation = wsdlOperation;
        wsdlOperation = operation;
        requestStepConfig.setInterface(operation.getInterface().getName());
        requestStepConfig.setOperation(operation.getName());

        if (oldOperation != null) {
            oldOperation.removePropertyChangeListener(this);
        }

        wsdlOperation.addPropertyChangeListener(this);

        initTestRequest(this.getConfig(), false);
        testRequest.setOperation(wsdlOperation);
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<? extends ModelItem> getChildren() {
        return testRequest == null ? Collections.EMPTY_LIST : testRequest.getAssertionList();
    }

    public PropertyExpansion[] getPropertyExpansions() {
        if (testRequest == null) {
            return new PropertyExpansion[0];
        }

        PropertyExpansionsResult result = new PropertyExpansionsResult(this, testRequest);

        result.extractAndAddAll("requestContent");
        result.extractAndAddAll("endpoint");
        result.extractAndAddAll("username");
        result.extractAndAddAll("password");
        result.extractAndAddAll("domain");

        StringToStringsMap requestHeaders = testRequest.getRequestHeaders();
        for (Map.Entry<String, List<String>> headerEntry : requestHeaders.entrySet()) {
            for (String value : headerEntry.getValue()) {
                result.extractAndAddAll(new HttpTestRequestStep.RequestHeaderHolder(headerEntry.getKey(), value,
                        testRequest), "value");
            }
        }

        testRequest.addWsaPropertyExpansions(result, testRequest.getWsaConfig(), this);
        testRequest.addJMSHeaderExpansions(result, testRequest.getJMSHeaderConfig(), this);
        return result.toArray(new PropertyExpansion[result.size()]);
    }

    public TestAssertion addAssertion(String type) {
        WsdlMessageAssertion result = testRequest.addAssertion(type);
        return result;
    }

    public void addAssertionsListener(AssertionsListener listener) {
        testRequest.addAssertionsListener(listener);
    }

    public TestAssertion cloneAssertion(TestAssertion source, String name) {
        return testRequest.cloneAssertion(source, name);
    }

    public String getAssertableContentAsXml() {
        return testRequest.getAssertableContentAsXml();
    }

    public String getAssertableContent() {
        return testRequest.getAssertableContent();
    }

    public AssertableType getAssertableType() {
        return testRequest.getAssertableType();
    }

    public TestAssertion getAssertionByName(String name) {
        return testRequest.getAssertionByName(name);
    }

    public List<TestAssertion> getAssertionList() {
        return testRequest.getAssertionList();
    }

    public AssertionStatus getAssertionStatus() {
        return testRequest.getAssertionStatus();
    }

    public Interface getInterface() {
        return wsdlOperation == null ? null : wsdlOperation.getInterface();
    }

    public WsdlOperation getOperation() {
        return wsdlOperation;
    }

    public TestStep getTestStep() {
        return this;
    }

    public void removeAssertion(TestAssertion assertion) {
        testRequest.removeAssertion(assertion);
    }

    public TestAssertion moveAssertion(int ix, int whereTo) {
        return testRequest.moveAssertion(ix, whereTo);
    }

    public void removeAssertionsListener(AssertionsListener listener) {
        testRequest.removeAssertionsListener(listener);
    }

    public Map<String, TestAssertion> getAssertions() {
        return testRequest.getAssertions();
    }

    @Override
    public void prepare(TestCaseRunner testRunner, TestCaseRunContext testRunContext) throws Exception {
        super.prepare(testRunner, testRunContext);

        testRequest.setResponse(null, testRunContext);

        for (TestAssertion assertion : testRequest.getAssertionList()) {
            assertion.prepare(testRunner, testRunContext);
        }
    }

    public String getDefaultAssertableContent() {
        return testRequest.getDefaultAssertableContent();
    }

    @SuppressWarnings("unchecked")
    public void resolve(ResolveContext<?> context) {
        super.resolve(context);

        if (wsdlOperation == null) {
            // not solved and we have it in list do not add it.
            if (context.hasThisModelItem(this, "Missing SOAP Operation in Project", requestStepConfig.getInterface()
                    + "/" + requestStepConfig.getOperation())) {
                return;
            }

            context.addPathToResolve(this, "Missing SOAP Operation in Project",
                    requestStepConfig.getInterface() + "/" + requestStepConfig.getOperation()).addResolvers(
                    new RemoveTestStepResolver(this), new ImportInterfaceResolver(this) {

                        @Override
                        protected boolean update() {
                            wsdlOperation = findWsdlOperation();
                            if (wsdlOperation == null) {
                                return false;
                            }

                            initTestRequest(getConfig(), false);
                            initRequestProperties();
                            setDisabled(false);
                            return true;
                        }
                    }, new ChangeOperationResolver(this, "Operation") {

                        @Override
                        public boolean update() {
                            WsdlOperation wsdlOperation = (WsdlOperation) getSelectedOperation();
                            if (wsdlOperation == null) {
                                return false;
                            }

                            setOperation(wsdlOperation);
                            initTestRequest(getConfig(), false);
                            initRequestProperties();
                            setDisabled(false);
                            return true;
                        }

                        protected Interface[] getInterfaces(WsdlProject project) {
                            List<WsdlInterface> interfaces = ModelSupport.getChildren(project, WsdlInterface.class);
                            return interfaces.toArray(new Interface[interfaces.size()]);

                        }

                    }
            );
        } else {
            testRequest.resolve(context);
            if (context.hasThisModelItem(this, "Missing SOAP Operation in Project", requestStepConfig.getInterface()
                    + "/" + requestStepConfig.getOperation())) {
                PathToResolve path = context.getPath(this, "Missing SOAP Operation in Project",
                        requestStepConfig.getInterface() + "/" + requestStepConfig.getOperation());
                path.setSolved(true);
            }
        }
    }

}
